package com.contactbook.web.client;

import java.util.HashMap;

import java.util.Set;

import com.contactbook.web.client.dto.ContactDTO;
import com.contactbook.web.client.dto.GroupDTO;
import com.contactbook.web.client.gwt.ContactFlexTable;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.MouseOutEvent;
import com.google.gwt.event.dom.client.MouseOutHandler;
import com.google.gwt.event.dom.client.MouseOverEvent;
import com.google.gwt.event.dom.client.MouseOverHandler;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.DecoratorPanel;
import com.google.gwt.user.client.ui.DisclosurePanel;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.VerticalPanel;


public class ListOfContactsWidget extends View {
	
	private class DeleteGroupClickHandler implements ClickHandler {

		private final int groupId;
		
		public DeleteGroupClickHandler(int groupId) {
			this.groupId = groupId;
		}
		@Override
		public void onClick(ClickEvent arg0) {
			contactBook.getCurrentSession().parameters.put(Constants.SessionParameterGroupId, groupId);
			contactBook.switchView("deleteGroup");
		}
	};
	
	private class UpdateGroupClickHandler implements ClickHandler {

		private final int groupId;
		
		public UpdateGroupClickHandler(int groupId) {
			this.groupId = groupId;
		}
		
		@Override
		public void onClick(ClickEvent arg0) {
			contactBook.getCurrentSession().parameters.put(Constants.SessionParameterGroupId, groupId);
			contactBook.switchView(Constants.UpdateGroupViewName);
		}
	};
	
	private class MouseOverContactHandler implements MouseOverHandler {
		
		private FlexTable contactTable;
				
		public MouseOverContactHandler(FlexTable contactTable) {
			this.contactTable = contactTable;
		}
		
		@Override
		public void onMouseOver(MouseOverEvent event) {
			for (int i=1; i<=4; i++)
			contactTable.getWidget(0, i).setVisible(true);
			
			contactTable.setStyleName("gwt-label-contactOnMouseOver");
		}
	};
	
	private class MouseOutContactHandler implements MouseOutHandler {
		
		private FlexTable contactTable;
		
		public MouseOutContactHandler(FlexTable contactTable) {
			this.contactTable = contactTable;
		}
		
		@Override
		public void onMouseOut(MouseOutEvent event) {
			for (int i=1; i<=4; i++)
				contactTable.getWidget(0, i).setVisible(false);
			contactTable.setStyleName("gwt-label-contactOnMouseOut");
		}
	};
	
	private class MouseOverContactOptionsHandler implements MouseOverHandler {
		
		private FlexTable contactTable;
		
		public MouseOverContactOptionsHandler(FlexTable contactTable) {
			this.contactTable = contactTable;
		}
		
		@Override
		public void onMouseOver(MouseOverEvent event) {					
			contactTable.setStyleName("gwt-label-contactOnMouseOver");
			for (int i=1; i<=4; i++)
				contactTable.getWidget(0, i).setVisible(true);
		}
	}
	
	private class MouseOutContactOptionsHandler implements MouseOutHandler {
		
		private FlexTable contactTable;
		
		public MouseOutContactOptionsHandler(FlexTable contactTable) {
			this.contactTable = contactTable;
		}
		
		@Override
		public void onMouseOut(MouseOutEvent event) {					
			contactTable.setStyleName("gwt-label-contactOnMouseOut");
			for (int i=1; i<=4; i++)
				contactTable.getWidget(0, i).setVisible(false);
		}
	}
	
	private class DeleteContactClickHandler implements ClickHandler {

		private int contactId;
		
		public DeleteContactClickHandler(int contactId) {
			this.contactId = contactId;
		}
		
		@Override
		public void onClick(ClickEvent arg0) {
			contactBook.getCurrentSession().parameters.put(Constants.SessionParameterContactId, contactId);
			contactBook.switchView(Constants.DeleteContactViewName);
		}		
	}
	
	private class UpdateContactClickHandler implements ClickHandler {

		private int contactId;
		
		public UpdateContactClickHandler(int contactId) {
			this.contactId = contactId;
		}
		
		@Override
		public void onClick(ClickEvent arg0) {
			contactBook.getCurrentSession().parameters.put(Constants.SessionParameterContactId, contactId);
			contactBook.switchView(Constants.UpdateContactViewName);
		}		
	}
	
	private VerticalPanel content;
	
	private HashMap<Integer, Set<ContactDTO>> contactsOfGroups = new HashMap<Integer, Set<ContactDTO>>();
	
	private final DisclosurePanel disclosurePanelContactsWNG;
	private final VerticalPanel panelGroups;
	
	private final static String TITLE = "Your contacts";
	
	private final static String DEFAULT_GROUP = "Default group";	
	private final static int DEFAULT_GROUP_ID = -1;
	
	public ListOfContactsWidget(ContactBook contactBook) {
		
		super(contactBook);	
		
		disclosurePanelContactsWNG = new DisclosurePanel(DEFAULT_GROUP);
		panelGroups = new VerticalPanel();
		
	}
	
	private class ClickOnAContactHandler implements ClickHandler {
		private int contactId;
		public void onClick(ClickEvent event) {
			contactBook.getCurrentSession().parameters.put(Constants.SessionParameterContactId, contactId);
			contactBook.switchView(Constants.ContactSheetViewName);
		}
		
		public void setContactId(int contactId) {
			this.contactId = contactId;
		}
	}

	@Override
	public VerticalPanel getContent() {
		
		if (contactBook.isLogged())	{
			disclosurePanelContactsWNG.clear();
			panelGroups.clear();
			return buildView();
		} else
			contactBook.switchView("login");
		return null;
	}
	
	public VerticalPanel buildView() {
		
		content = new VerticalPanel();
		
		getContactsWithoutGroup();
		getGroups();

		DecoratorPanel panelGroupWNG = new DecoratorPanel();
		panelGroupWNG.add(disclosurePanelContactsWNG);
		panelGroups.add(panelGroupWNG);
		
		content.add(panelGroups);
	    
		HorizontalPanel panelButtons = new HorizontalPanel();
		panelButtons.setSpacing(12);

		// Add a contact button
		HorizontalPanel panelAddContact = new HorizontalPanel();
		panelAddContact.setWidth("180px");
		panelAddContact.setStyleName("gwt-label-addContactPanel");
		panelAddContact.setSpacing(6);

		Image addContactIcon = new Image(Constants.IconAddContactPath);
		addContactIcon.setSize(Constants.IconSizeConstant, Constants.IconSizeConstant);

		Label addContactLabel = new Label("Add a contact");
		addContactLabel.setStyleName("gwt-label-addContactIcon");
		addContactLabel.addClickHandler(new ClickHandler() {
			
			@Override
			public void onClick(ClickEvent event) {
				contactBook.switchView("addContact");
			}
		});

		panelAddContact.add(addContactIcon);
		panelAddContact.add(addContactLabel);


		// Add a group button
		HorizontalPanel panelAddGroup = new HorizontalPanel();
		panelAddGroup.setWidth("180");
		panelAddGroup.setStyleName("gwt-label-addContactPanel");
		panelAddGroup.setSpacing(6);

		Image addGroupIcon = new Image(Constants.IconAddGroupPath);
		addGroupIcon.setSize(Constants.IconSizeConstant, Constants.IconSizeConstant);

		Label addGroupLabel = new Label("Add a group");
		addGroupLabel.setStyleName("gwt-label-addGroupIcon");
		addGroupLabel.addClickHandler(new ClickHandler() {
		
			@Override
			public void onClick(ClickEvent event) {
				contactBook.switchView("addGroup");
			}
		});

		panelAddGroup.add(addGroupIcon);
		panelAddGroup.add(addGroupLabel);
		  
		panelButtons.add(panelAddContact);
		panelButtons.add(panelAddGroup);
	
		content.add(panelButtons);
		
		return content;
	}

	@Override
	public String getTitle() {
		return TITLE;
	}
	
	public void getContactsByGroup(final GroupDTO groupDTO) {

		final AsyncCallback<Set<ContactDTO>> callback = new AsyncCallback<Set<ContactDTO>>() {
			
			@SuppressWarnings("deprecation")
			public void onFailure(Throwable caught) {
				content = new ErrorPanel();
			}
			
			public void onSuccess(Set<ContactDTO> result) {	 	
			 	DecoratorPanel panelGroup = new DecoratorPanel();
			 	
			    DisclosurePanel disclosurePanelContacts = new DisclosurePanel(groupDTO.getName());
			    disclosurePanelContacts.setAnimationEnabled(true);
			    
			 	HorizontalPanel panelHeader = new HorizontalPanel();
			 	
				Image groupIcon = new Image(Constants.IconGroupPath);
				groupIcon.setSize(Constants.IconSizeConstant, Constants.IconSizeConstant);
				
			 	FlowPanel panelName = new FlowPanel();
					 	
			 	Label groupName = new Label(groupDTO.getName());
			 	groupName.setStyleName("gwt-label-groupNameHeader");
			 	panelName.add(groupName);			
			 	
			 	Image deleteGroupButton = new Image(Constants.IconDeleteGroupPath);
			 	deleteGroupButton.setTitle(Constants.IconDeleteGroupTitle);
			 	deleteGroupButton.setSize(Constants.IconSizeConstant, Constants.IconSizeConstant);
			 	deleteGroupButton.addClickHandler(new DeleteGroupClickHandler(groupDTO.getId()));
			 	
			 	Label labelGroupIconsSpace = new Label(" ");
			 	
			 	Image updateGroupButton = new Image(Constants.IconUpdateGroupPath);
			 	updateGroupButton.setTitle(Constants.IconUpdateGroupTitle);
			 	updateGroupButton.setSize(Constants.IconSizeConstant, Constants.IconSizeConstant);
			 	updateGroupButton.addClickHandler(new UpdateGroupClickHandler(groupDTO.getId()));
			 	
			 	if (result.size() != 0) {
			 		Label groupNbContacts = new Label("(" + result.size() +" contact" + ((result.size()==1)?")":"s)"));
			 		groupNbContacts.setStyleName("gwt-label-groupNbContacts");
			 		panelName.add(groupNbContacts);
			 	}
			 	panelName.setWidth(Constants.GroupNameHeaderWidth);
			 	
			 	panelHeader.add(groupIcon);
			 	panelHeader.add(panelName);
			 	panelHeader.add(deleteGroupButton);
			 	panelHeader.add(labelGroupIconsSpace);
			 	panelHeader.add(updateGroupButton);
			 	
			 	disclosurePanelContacts.setHeader(panelHeader);
			    
			    VerticalPanel panelContacts = new VerticalPanel();
				panelContacts.setSpacing(3);
				
				for (ContactDTO contactDTO : result) {
					HorizontalPanel contactPanel = new HorizontalPanel();
					
					Image contactIcon = new Image(Constants.IconContactPath);
					contactIcon.setSize(Constants.IconSizeConstant, Constants.IconSizeConstant);
					
					ContactFlexTable tableContact = new ContactFlexTable();
					tableContact.setCellSpacing(0);
					tableContact.setCellPadding(0);
					
					Label contactLabel = new Label();
					contactLabel.setHeight(Constants.ContactNameLabelHeight);
					contactLabel.setWidth(Constants.ContactNameLabelWidth);
					contactLabel.setText("   " + contactDTO.getFirstName() + " " + contactDTO.getLastName());
					
					ClickOnAContactHandler handler = new ClickOnAContactHandler();
					handler.setContactId(contactDTO.getId());
					contactLabel.addClickHandler(handler);
					
					tableContact.setWidget(0, 0, contactLabel);
									
					Image deleteContactIcon = new Image(Constants.IconDeleteContactPath);
					deleteContactIcon.setTitle(Constants.IconDeleteContactTitle);
					deleteContactIcon.setSize(Constants.IconSizeConstant, Constants.IconSizeConstant);
					tableContact.setWidget(0, 1, deleteContactIcon);
					
					Label labelSpace = new Label("  ");
					labelSpace.setHeight(Constants.ContactNameLabelHeight);
					tableContact.setWidget(0, 2, labelSpace);
					
					Image updateContactIcon = new Image(Constants.IconUpdateContactPath);
					updateContactIcon.setTitle(Constants.IconUpdateContactTitle);
					updateContactIcon.setSize(Constants.IconSizeConstant, Constants.IconSizeConstant);
					tableContact.setWidget(0, 3, updateContactIcon);
					
					Label labelSpaceBorder = new Label("  ");
					labelSpaceBorder.setHeight(Constants.ContactNameLabelHeight);
					tableContact.setWidget(0, 4, labelSpaceBorder);
					
					deleteContactIcon.addMouseOverHandler(new MouseOverContactOptionsHandler(tableContact));
					deleteContactIcon.addMouseOutHandler(new MouseOutContactOptionsHandler(tableContact));
					deleteContactIcon.addClickHandler(new DeleteContactClickHandler(contactDTO.getId()));
					
					labelSpace.addMouseOverHandler(new MouseOverContactOptionsHandler(tableContact));
					labelSpace.addMouseOutHandler(new MouseOutContactOptionsHandler(tableContact));
					
					updateContactIcon.addMouseOverHandler(new MouseOverContactOptionsHandler(tableContact));
					updateContactIcon.addMouseOutHandler(new MouseOutContactOptionsHandler(tableContact));
					updateContactIcon.addClickHandler(new UpdateContactClickHandler(contactDTO.getId()));
					
					labelSpaceBorder.addMouseOverHandler(new MouseOverContactOptionsHandler(tableContact));
					labelSpaceBorder.addMouseOutHandler(new MouseOutContactOptionsHandler(tableContact));
					
					deleteContactIcon.setVisible(false);
					labelSpace.setVisible(false);
					updateContactIcon.setVisible(false);
					labelSpaceBorder.setVisible(false);
										
					contactLabel.addMouseOverHandler(new MouseOverContactHandler(tableContact));					
					contactLabel.addMouseOutHandler(new MouseOutContactHandler(tableContact));

					contactPanel.add(contactIcon);
					contactPanel.add(tableContact);
					panelContacts.add(contactPanel);
				}
				
			    disclosurePanelContacts.setContent(panelContacts);
			    panelGroup.add(disclosurePanelContacts);
			    panelGroups.add(panelGroup);
			    
			}
		};
		contactBook.getContactService().getContacts(groupDTO.getId(), contactBook.getCurrentSession().getLogin(), contactBook.getCurrentSession().getPassword(), callback);
	}

	public void getContactsWithoutGroup() {
		final AsyncCallback<Set<ContactDTO>> callback = new AsyncCallback<Set<ContactDTO>>() {
			
			@SuppressWarnings("deprecation")
			public void onFailure(Throwable caught) {
				content = new ErrorPanel();
			}
			
			public void onSuccess(Set<ContactDTO> result) {
				
			 	contactsOfGroups.put(DEFAULT_GROUP_ID, result);			 	
			 	
			 	disclosurePanelContactsWNG.setAnimationEnabled(true);
			 	
			 	HorizontalPanel panelHeader = new HorizontalPanel();
			 	
				Image groupIcon = new Image(Constants.IconGroupPath);
				groupIcon.setSize(Constants.IconSizeConstant, Constants.IconSizeConstant);
				
			 	FlowPanel panelName = new FlowPanel();
			 					
			 	Label groupName = new Label(DEFAULT_GROUP);
			 	groupName.setStyleName("gwt-label-groupNameHeader");
			 	panelName.add(groupName);
			 	
			 	if (result.size() != 0) {
			 		Label groupNbContacts = new Label("(" + result.size() +" contact" + ((result.size()==1)?")":"s)"));
			 		groupNbContacts.setStyleName("gwt-label-groupNbContacts");
			 		panelName.add(groupNbContacts);
			 	}
			 	panelName.setWidth(Constants.GroupWNCNameHeaderWidth);
			 	
			 	panelHeader.add(groupIcon);
			 	panelHeader.add(panelName);
			 	
			 	disclosurePanelContactsWNG.setHeader(panelHeader);
			 	
			    VerticalPanel panelContactsWNG = new VerticalPanel();
			    panelContactsWNG.setSpacing(3);
							
				for (ContactDTO contactDTO : contactsOfGroups.get(DEFAULT_GROUP_ID)) {
					HorizontalPanel contactPanel = new HorizontalPanel();
					
					Image contactIcon = new Image(Constants.IconContactPath);
					contactIcon.setSize(Constants.IconSizeConstant, Constants.IconSizeConstant);
					
					FlexTable tableContact = new FlexTable();
					tableContact.setCellSpacing(0);
					tableContact.setCellPadding(0);
					
					Label contactLabel = new Label();
					contactLabel.setWidth(Constants.ContactNameLabelWidth);
					contactLabel.setHeight(Constants.ContactNameLabelHeight);
					contactLabel.setText("   " + contactDTO.getFirstName() + " " + contactDTO.getLastName());
					
					ClickOnAContactHandler handler = new ClickOnAContactHandler();
					handler.setContactId(contactDTO.getId());
					contactLabel.addClickHandler(handler);
					
					tableContact.setWidget(0, 0, contactLabel);
					tableContact.getCellFormatter().setHeight(0, 0, Constants.ContactNameLabelHeight);
					
					Image deleteContactIcon = new Image(Constants.IconDeleteContactPath);
					deleteContactIcon.setTitle(Constants.IconDeleteContactTitle);
					deleteContactIcon.setSize(Constants.IconSizeConstant, Constants.IconSizeConstant);
					tableContact.setWidget(0, 1, deleteContactIcon);
					
					Label labelSpace = new Label("  ");
					labelSpace.setHeight(Constants.ContactNameLabelHeight);
					tableContact.setWidget(0, 2, labelSpace);
					
					Image updateContactIcon = new Image(Constants.IconUpdateContactPath);
					updateContactIcon.setTitle(Constants.IconUpdateContactTitle);
					updateContactIcon.setSize(Constants.IconSizeConstant, Constants.IconSizeConstant);
					tableContact.setWidget(0, 3, updateContactIcon);
					
					Label labelSpaceBorder = new Label("  ");
					labelSpaceBorder.setHeight(Constants.ContactNameLabelHeight);
					tableContact.setWidget(0, 4, labelSpaceBorder);
					
					deleteContactIcon.addMouseOverHandler(new MouseOverContactOptionsHandler(tableContact));
					deleteContactIcon.addMouseOutHandler(new MouseOutContactOptionsHandler(tableContact));
					deleteContactIcon.addClickHandler(new DeleteContactClickHandler(contactDTO.getId()));
					
					labelSpace.addMouseOverHandler(new MouseOverContactOptionsHandler(tableContact));
					labelSpace.addMouseOutHandler(new MouseOutContactOptionsHandler(tableContact));
					
					updateContactIcon.addMouseOverHandler(new MouseOverContactOptionsHandler(tableContact));
					updateContactIcon.addMouseOutHandler(new MouseOutContactOptionsHandler(tableContact));
					updateContactIcon.addClickHandler(new UpdateContactClickHandler(contactDTO.getId()));
					
					labelSpaceBorder.addMouseOverHandler(new MouseOverContactOptionsHandler(tableContact));
					labelSpaceBorder.addMouseOutHandler(new MouseOutContactOptionsHandler(tableContact));
					
					deleteContactIcon.setVisible(false);
					labelSpace.setVisible(false);
					updateContactIcon.setVisible(false);
					labelSpaceBorder.setVisible(false);
										
					contactLabel.addMouseOverHandler(new MouseOverContactHandler(tableContact));					
					contactLabel.addMouseOutHandler(new MouseOutContactHandler(tableContact));
					
					contactPanel.add(contactIcon);
					contactPanel.add(tableContact);
					panelContactsWNG.add(contactPanel);
				}
				
			    disclosurePanelContactsWNG.setContent(panelContactsWNG);
			}
		};
		contactBook.getContactService().getContactsWithoutGroup(contactBook.getCurrentSession().getLogin(), contactBook.getCurrentSession().getPassword(), callback);
	}
	
	private void getGroups() {

	    final AsyncCallback<Set<GroupDTO>> callback = new AsyncCallback<Set<GroupDTO>>() {

			@SuppressWarnings("deprecation")
			@Override
			public void onFailure(Throwable caught) {
				content = new ErrorPanel();
			}

			@Override
			public void onSuccess(Set<GroupDTO> result) {
				for (GroupDTO groupDTO : result)					
					getContactsByGroup(groupDTO);
			}
		};
		contactBook.getGroupService().getGroups(contactBook.getCurrentSession().getLogin(), contactBook.getCurrentSession().getPassword(), callback);
	}
}
